package org.enhance.common.util.compression;

import java.io.*;
import java.util.Arrays;
import java.util.zip.ZipEntry;
import java.util.zip.ZipInputStream;
import java.util.zip.ZipOutputStream;

import org.enhance.common.exception.EnhanceRuntimeException;
import org.enhance.common.util.FileUtil;

import lombok.extern.slf4j.Slf4j;

@Slf4j
public class ZipUtil {

	private ZipUtil() {
		throw new IllegalStateException("Constant class");
	}

	private static byte[] ZIP_HEADER_1 = new byte[] { 80, 75, 3, 4 };
	private static byte[] ZIP_HEADER_2 = new byte[] { 80, 75, 5, 6 };

	public static boolean validateZip(File srcFile) {
		boolean temp = srcFile!=null && !srcFile.isDirectory();
		if(!temp) {
			return false;
		}
		// 判断文件名是否为zip
		temp = FileUtil.getExtension(srcFile.getName()).equalsIgnoreCase("zip");
		if(!temp) {
			return false;
		}

		try{
			return validateZip(new FileInputStream(srcFile));
		} catch (Exception e) {
			throw new RuntimeException(e);
		}
	}

	public static boolean validateZip(InputStream inputStream) {
		if(inputStream == null) { return false; }

		// 判断文件是否zip压缩
		boolean result = false;
		try {
			byte[] buffer = new byte[4];
			int length = inputStream.read(buffer, 0, 4);
			if (length == 4) {
				result = (Arrays.equals(ZIP_HEADER_1, buffer)) || (Arrays.equals(ZIP_HEADER_2, buffer));
			}
		} catch (Exception e) {
			throw new EnhanceRuntimeException(e);
		}

		return result;
	}


	public static void zip(File srcFile, String outputFile) {
		//创建zip输出流
		try (ZipOutputStream out = new ZipOutputStream(new FileOutputStream(outputFile));
			 //创建缓冲输出流
			 BufferedOutputStream bos = new BufferedOutputStream(out)) {
			compress(out, bos, srcFile,null);
		} catch (Exception e) {
			throw new EnhanceRuntimeException(e);
		}
	}
	/**
	 * @param name 压缩文件名，可以写为null保持默认
	 */
	//递归压缩
	private static void compress(ZipOutputStream out, BufferedOutputStream bos, File input, String name) throws IOException {
		if (name == null) {
			name = input.getName();
		}
		//如果路径为目录（文件夹）
		if (input.isDirectory()) {
			//取出文件夹中的文件（或子文件夹）
			File[] flist = input.listFiles();

			if (flist.length == 0) { //如果文件夹为空，则只需在目的地zip文件中写入一个目录进入
				out.putNextEntry(new ZipEntry(name + "/"));
			} else { //如果文件夹不为空，则递归调用compress，文件夹中的每一个文件（或文件夹）进行压缩
				for (int i = 0; i < flist.length; i++) {
					compress(out, bos, flist[i], name + "/" + flist[i].getName());
				}
			}
		} else { //如果不是目录（文件夹），即为文件，则先写入目录进入点，之后将文件写入zip文件中
			out.putNextEntry(new ZipEntry(name));
			try (FileInputStream fos = new FileInputStream(input);
				 BufferedInputStream bis = new BufferedInputStream(fos)) {
				int len=-1;
				//将源文件写入到zip文件中
				byte[] buf = new byte[1024];
				while ((len = bis.read(buf)) != -1) {
					bos.write(buf,0,len);
				}
			}
		}
	}

	public static void unZip(File srcFile, String destDirPath) {
		if (!srcFile.exists() || srcFile.isDirectory()) {
			return;
		}
		try {
			unZip(new FileInputStream(srcFile), destDirPath);
		} catch (Exception e) {
			throw new RuntimeException(e);
		}
	}

	public static void unZip(InputStream inputStream, String destDirPath) {
		if(inputStream == null) { return; }
		try(ZipInputStream zIn = new ZipInputStream(inputStream)) {
			ZipEntry entry = null;
			File file = null;
			while ((entry = zIn.getNextEntry()) != null) {
				if (!entry.isDirectory()) {
					file = new File(destDirPath, entry.getName());
					if (!file.exists()) {
						new File(file.getParent()).mkdirs();//创建此文件的上级目录
					}
					try (OutputStream out = new FileOutputStream(file);
						 BufferedOutputStream bos = new BufferedOutputStream(out)) {
						int len = -1;
						byte[] buf = new byte[1024];
						while ((len = zIn.read(buf)) != -1) {
							bos.write(buf, 0, len);
						}
					}
				}
			}
		} catch (Exception e) {
			throw new RuntimeException(e);
		}
	}
}